import json
import xml.etree.ElementTree as ET
from xml.dom import minidom
import os
import datetime

def json_to_opcua_xml(json_data):
    # 创建根节点
    ns = {'xsi': 'http://www.w3.org/2001/XMLSchema-instance',
          'uax': 'http://opcfoundation.org/UA/2008/02/Types.xsd',
          'si': 'http://www.siemens.com/OPCUA/2017/SimaticNodeSetExtensions'}
    
    root = ET.Element('UANodeSet', 
                     attrib={'xmlns': 'http://opcfoundation.org/UA/2011/03/UANodeSet.xsd',
                             'xmlns:xsi': ns['xsi'],
                             'xmlns:uax': ns['uax'],
                             'xmlns:si': ns['si'],
                             'LastModified': datetime.datetime.now().isoformat()
                                 })

    # 添加命名空间
    namespaces = ET.SubElement(root, 'NamespaceUris')
    ET.SubElement(namespaces, 'Uri').text = "http://opcfoundation.org/UA/Machinery/Jobs/"
    ET.SubElement(namespaces, 'Uri').text = "http://opcfoundation.org/UA/Machinery/Result/"
    ET.SubElement(namespaces, 'Uri').text = "http://openharmony.dna.sjtu.edu.cn/"

    # 添加模型
    models = ET.SubElement(root, 'Models')
    model = ET.SubElement(models, 'Model', 
                         attrib={'ModelUri': 'http://openharmony.dna.sjtu.edu.cn/',
                                 'PublicationDate': '2024-10-12T20:45:03+08:00',
                                 'Version': '1.00'})
    # ET.SubElement(model, 'RequiredModel', 
    #              attrib={'ModelUri': 'http://opcfoundation.org/UA/',
    #                      'PublicationDate': '2022-06-28T00:00:00Z',
    #                      'Version': '1.05.02'})

    # 添加别名
    aliases = ET.SubElement(root, 'Aliases')
    if 'aliases' in json_data:
        for alias, value in json_data['aliases'].items():
            if alias.startswith('i=') or alias.startswith('ns='):
                ET.SubElement(aliases, 'Alias', attrib={'Alias': value}).text = alias

    # 添加设备节点
    device_info = json_data.get('deviceInfo', {})
    if(device_info.get('NodeId') != 'i=85'):
        device_node = ET.SubElement(root, 'UAObject', 
                               attrib={'NodeId': device_info.get('NodeId', 'Default NodeId'),
                                       'BrowseName': f"3:{device_info.get('deviceName', 'Default deviceName')}",
                                    #    **({'ParentNodeId': device_info.get('ParentNodeId')} if device_info.get('ParentNodeId') else {"i=85"})})
                                       **({'ParentNodeId': "i=85"})})
        ET.SubElement(device_node, 'DisplayName').text = device_info.get('deviceName', 'Default deviceName')
        
        refs = ET.SubElement(device_node, 'References')
        for ref in device_info['References']['Reference']:
            ref_type = ref['ReferenceType']
            alias_value = next((k for k, v in json_data['aliases'].items() if v == ref['text']), ref['text'])
            ET.SubElement(refs, 'Reference', 
                        attrib={'ReferenceType': ref_type}).text = alias_value
    
    
    # 添加服务
    for service in device_info.get('services', []):
        service_node = ET.SubElement(root, 'UAObject',
                                   attrib={'NodeId': service.get('NodeId', 'Default NodeId'),
                                           'BrowseName': f"3:{service.get('deviceName', 'Default deviceName')}",
                                           'ParentNodeId': service.get('ParentNodeId', 'No ParentNodeId')})
        ET.SubElement(service_node, 'DisplayName').text = service.get('serviceId', 'Default serviceId')
        
        service_refs = ET.SubElement(service_node, 'References')
        for ref in service['References']['Reference']:
            ref_type = ref['ReferenceType']
            alias_value = next((k for k, v in json_data['aliases'].items() if v == ref['text']), ref['text'])
            ET.SubElement(service_refs, 'Reference',
                         attrib={'ReferenceType': ref_type}).text = alias_value
        
        # 添加特征
        for char in service.get('characteristics', []):
            var_attribs = {
                'NodeId': char.get('NodeId', ''),
                'BrowseName': f"3:{char.get('characteristicName', 'Default characteristicName')}",
                'ParentNodeId': char.get('ParentNodeId', 'No ParentNodeId'),
                'DataType': 'Int32' if char.get('characteristicType') == 'Int' else char.get('characteristicType', 'String'),
                'ValueRank': '-1'  # 默认标量
            }
            
            var_node = ET.SubElement(root, 'UAVariable', attrib=var_attribs)
            ET.SubElement(var_node, 'DisplayName').text = char.get('characteristicName', '').split(':')[-1]

            char_refs = ET.SubElement(var_node, 'References')
            for ref in char['References']['Reference']:
                ref_type = ref['ReferenceType']
                alias_value = next((k for k, v in json_data['aliases'].items() if v == ref['text']), ref['text'])
                ET.SubElement(char_refs, 'Reference',
                            attrib={'ReferenceType': ref_type}).text = alias_value
            
            # 添加值
            value_node = ET.SubElement(var_node, 'Value')
            if isinstance(char.get('value'), int):
                ET.SubElement(value_node, 'uax:Int32').text = str(char.get('value', 0))
            else:
                ET.SubElement(value_node, 'uax:String').text = str(char.get('value', ''))

    # 格式化输出
    xml_str = ET.tostring(root, encoding='utf-8', method='xml')
    dom = minidom.parseString(xml_str)
    return dom.toprettyxml(indent='    ', encoding='utf-8').decode('utf-8')

def convertPipeLine(base, path):
    # 读取JSON文件  
    with open(os.path.join(base,'unified_define', path) ) as f:
        json_data = json.load(f)

    xml_output = json_to_opcua_xml(json_data)
    # 写入XML文件
    with open(os.path.join(base,'opcua_define', path.rsplit('.', 1)[0] + '-opcua.xml'), 'wb') as xml_file:
        xml_file.write(xml_output.encode('utf-8'))
    print('OH-JSON文件 '+path+' 已成功转换为OPC-UA-XML格式。')
    
convertPipeLine(os.path.dirname(__file__), "OpenharmonyDna-unified.json")
convertPipeLine(os.path.dirname(__file__), "example-unified.json")
convertPipeLine(os.path.dirname(__file__), "DNA-unified.json")
convertPipeLine(os.path.dirname(__file__), "GibhDemo2-unified.json")